Factory Pattern একটি জনপ্রিয় Creational Design Pattern, যা নির্দিষ্ট টাইপের অবজেক্ট তৈরি করার জন্য ব্যবহৃত হয়। Generics এর সাথে Factory Pattern ব্যবহার করলে কোড আরও ডাইনামিক, টাইপ-সেফ এবং পুনঃব্যবহারযোগ্য হয়।
Factory Pattern: সংক্ষিপ্ত ব্যাখ্যা
Factory Pattern এর মূল ধারণা হলো অবজেক্ট তৈরির কাজ সরাসরি ক্লায়েন্ট ক্লাসে না রেখে, একটি ফ্যাক্টরি ক্লাসের মাধ্যমে পরিচালনা করা। এটি কোডের Encapsulation বৃদ্ধি করে এবং Object Creation Logic কে মডুলার করে তোলে।
Generics এবং Factory Pattern এর সমন্বয়
1. Generic Factory Pattern এর উদাহরণ
// Generic Factory Class
public class Factory<T> {
private Class<T> type;
public Factory(Class<T> type) {
this.type = type;
}
public T createInstance() {
try {
return type.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new RuntimeException("Error creating instance of: " + type.getName(), e);
}
}
}
// Example Usage
class Product {
public void display() {
System.out.println("Product created!");
}
}
public class Main {
public static void main(String[] args) {
Factory<Product> productFactory = new Factory<>(Product.class);
Product product = productFactory.createInstance();
product.display(); // Output: Product created!
}
}
বৈশিষ্ট্য:
- Generic Parameter
T: ফ্যাক্টরি ক্লাসটি যেকোনো টাইপের অবজেক্ট তৈরি করতে পারে। - Runtime Flexibility:
Class<T>প্যারামিটার ব্যবহার করে ডাইনামিক অবজেক্ট তৈরি করা যায়। - Type Safety: কম্পাইল টাইমে টাইপ চেকিং নিশ্চিত করে।
2. Factory Pattern এর সাথে Bounded Generics
যদি কোনো নির্দিষ্ট টাইপ বা টাইপের সীমা নির্ধারণ করতে হয়, তাহলে Bounded Generics ব্যবহার করা যেতে পারে।
// Bounded Generic Factory Class
public class BoundedFactory<T extends Number> {
private Class<T> type;
public BoundedFactory(Class<T> type) {
this.type = type;
}
public T createInstance() {
try {
return type.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new RuntimeException("Error creating instance of: " + type.getName(), e);
}
}
}
// Example Usage
public class Main {
public static void main(String[] args) {
BoundedFactory<Integer> integerFactory = new BoundedFactory<>(Integer.class);
// Integer instance তৈরি করা সম্ভব নয় কারণ Integer এর No-Arg Constructor নেই।
}
}
বৈশিষ্ট্য:
T extends Number: টাইপটি শুধুমাত্রNumberবা তার সাবক্লাস হতে পারে।- এটি টাইপ ইনস্ট্যান্স তৈরি করতে নির্ধারিত টাইপের মধ্যেই সীমাবদ্ধ।
3. Factory Pattern এর মাধ্যমে Collections তৈরি
Generics এর সাথে Factory Pattern ব্যবহার করে ডাইনামিকভাবে Collections তৈরি করা যায়।
import java.util.ArrayList;
import java.util.List;
public class CollectionFactory<T> {
public List<T> createList() {
return new ArrayList<>();
}
}
// Example Usage
public class Main {
public static void main(String[] args) {
CollectionFactory<String> stringListFactory = new CollectionFactory<>();
List<String> stringList = stringListFactory.createList();
stringList.add("Hello");
stringList.add("Generics");
System.out.println(stringList); // Output: [Hello, Generics]
}
}
4. Factory Pattern এর মাধ্যমে Singleton Object তৈরি
Generics এর সাথে Factory Pattern ব্যবহার করে Singleton Object তৈরি করা সম্ভব।
// Generic Singleton Factory
public class SingletonFactory<T> {
private T instance;
private Class<T> type;
public SingletonFactory(Class<T> type) {
this.type = type;
}
public T getInstance() {
if (instance == null) {
try {
instance = type.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new RuntimeException("Error creating instance of: " + type.getName(), e);
}
}
return instance;
}
}
// Example Usage
class Config {
public void display() {
System.out.println("Config loaded!");
}
}
public class Main {
public static void main(String[] args) {
SingletonFactory<Config> configFactory = new SingletonFactory<>(Config.class);
Config config1 = configFactory.getInstance();
Config config2 = configFactory.getInstance();
config1.display(); // Output: Config loaded!
// Both instances are the same
System.out.println(config1 == config2); // Output: true
}
}
5. Type Parameterized Factory Method
Factory Pattern এর সাথে জেনেরিক মেথড ব্যবহার করলে কোড আরও সংক্ষিপ্ত এবং সহজবোধ্য হয়।
public class FactoryUtil {
public static <T> T createInstance(Class<T> type) {
try {
return type.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new RuntimeException("Error creating instance of: " + type.getName(), e);
}
}
}
// Example Usage
class User {
public void display() {
System.out.println("User created!");
}
}
public class Main {
public static void main(String[] args) {
User user = FactoryUtil.createInstance(User.class);
user.display(); // Output: User created!
}
}
Factory Pattern এবং Generics এর সুবিধা
- Code Reusability: Generics ব্যবহার করে ফ্যাক্টরি ক্লাস বা মেথড বিভিন্ন টাইপের জন্য পুনঃব্যবহারযোগ্য।
- Type Safety: কম্পাইল টাইমে টাইপ চেকিং নিশ্চিত করে, রানটাইম ত্রুটির ঝুঁকি কমায়।
- Flexibility: যেকোনো টাইপের অবজেক্ট ডাইনামিকভাবে তৈরি করা যায়।
- Encapsulation: অবজেক্ট তৈরির লজিক ক্লায়েন্ট কোড থেকে আলাদা করা যায়।
Factory Pattern এবং Generics ব্যবহার করার সময় সতর্কতা
- Type Erasure এর সীমাবদ্ধতা:
- Generics টাইপের তথ্য রানটাইমে হারিয়ে যায়। ফলে কিছু সময়ে ক্লাস টাইপ (
Class<T>) প্যারামিটার পাস করতে হয়।
- Generics টাইপের তথ্য রানটাইমে হারিয়ে যায়। ফলে কিছু সময়ে ক্লাস টাইপ (
- Reflection এর ওভারহেড:
- Generics এর মাধ্যমে অবজেক্ট তৈরিতে Reflection ব্যবহৃত হলে পারফরম্যান্স কমতে পারে।
- No-Arg Constructor প্রয়োজন:
- Factory Pattern ব্যবহার করার জন্য ক্লাসে ডিফল্ট (No-Argument) কন্সট্রাক্টর থাকা আবশ্যক।
Generics এর সাথে Factory Pattern ব্যবহার করলে কোড ডাইনামিক, টাইপ-সেফ এবং পুনঃব্যবহারযোগ্য হয়। এটি অবজেক্ট তৈরির প্রক্রিয়া সহজ করে এবং জাভার প্রোগ্রামিং আরও কার্যকর করে তোলে। সঠিক নকশায় এই সমন্বয় ব্যবহার করলে পারফরম্যান্স বাড়ানোর পাশাপাশি জটিলতাও হ্রাস পায়।
Read more